﻿using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Linq;
using Xlsx.ComponentModel;
using Xlsx.ComponentModel.Enums;
using Xlsx.DataBinder.Extensions;

namespace Xslx.DataBinder.Tests.DataBinder.Extensions
{
    [TestClass]
    public class PropertyInfoExtensionsTest
    {
        [TestMethod]
        public void TestIsXlsxBindable()
        {
            var bindable = new Bindable();
            var propertyInfoWithoutAttri = bindable.GetType().GetProperties().Single(x => x.Name == "StringBindablePropertyWithoutAttrib");
            var propertyInfo = bindable.GetType().GetProperties().Single(x => x.Name == "StringBindableProperty");

            Assert.IsTrue(propertyInfo.IsXlsxBindable());
            Assert.IsTrue(propertyInfoWithoutAttri.IsXlsxBindable());
        }

        [TestMethod]
        public void TestIsNotXlsxBindable()
        {
            var bindable = new Bindable();
            var propertyInfo = bindable.GetType().GetProperties().Single(x => x.Name == "NonBindableProperty");

            Assert.IsFalse(propertyInfo.IsXlsxBindable());
        }

        [TestMethod]
        public void TestGetXlsxBindableInfoWithoutAttrib()
        {
            var bindable = new Bindable();

            var expectedStringWithoutAttrib = new XlsxBindableInfo
                {
                ColumnName = "StringBindablePropertyWithoutAttrib",
                Order = 0,
                Type = XlsxDataType.String
            };

            var expectedNumericWithoutAttrib = new XlsxBindableInfo
                {
                ColumnName = "NumericBindablePropertyWithoutAttrib",
                Order = 0,
                Type = XlsxDataType.Numeric
            };

            var expectedBoolWithoutAttrib = new XlsxBindableInfo
                {
                ColumnName = "BoolBindablePropertyWithoutAttrib",
                Order = 0,
                Type = XlsxDataType.Boolean
            };

            var expectedDateTimeWithoutAttrib = new XlsxBindableInfo
                {
                ColumnName = "DateTimeBindablePropertyWithoutAttrib",
                Order = 0,
                Type = XlsxDataType.DateTime
            };

            var expectedObjectWithoutAttrib = new XlsxBindableInfo
                {
                ColumnName = "ObjectBindablePropertyWithoutAttrib",
                Order = 0,
                Type = XlsxDataType.Object
            };

            var stringPropertyWithoutAttrib = bindable.GetType().GetProperties().Single(x => x.Name == "StringBindablePropertyWithoutAttrib");
            var numericPropertyWithoutAttrib = bindable.GetType().GetProperties().Single(x => x.Name == "NumericBindablePropertyWithoutAttrib");
            var boolPropertyWithoutAttrib = bindable.GetType().GetProperties().Single(x => x.Name == "BoolBindablePropertyWithoutAttrib");
            var dateTimePropertyWithoutAttrib = bindable.GetType().GetProperties().Single(x => x.Name == "DateTimeBindablePropertyWithoutAttrib");
            var objectPropertyWithoutAttrib = bindable.GetType().GetProperties().Single(x => x.Name == "ObjectBindablePropertyWithoutAttrib");
            var nonePropertyWithoutAttrib = bindable.GetType().GetProperties().Single(x => x.Name == "NoneBindablePropertyWithoutAttrib");
            
            var actualStringWithoutAttrib = stringPropertyWithoutAttrib.GetXlsxBindableInfo();
            var actualNumericWithoutAttrib = numericPropertyWithoutAttrib.GetXlsxBindableInfo();
            var actualBoolWithoutAttrib = boolPropertyWithoutAttrib.GetXlsxBindableInfo();
            var actualDateTimeWithoutAttrib = dateTimePropertyWithoutAttrib.GetXlsxBindableInfo();
            var actualObjectWithoutAttrib = objectPropertyWithoutAttrib.GetXlsxBindableInfo();
            var actualNoneWithoutAttrib = nonePropertyWithoutAttrib.GetXlsxBindableInfo();

            Assert.AreEqual(expectedStringWithoutAttrib.ColumnName, actualStringWithoutAttrib.ColumnName);
            Assert.AreEqual(expectedStringWithoutAttrib.Order, actualStringWithoutAttrib.Order);
            Assert.AreEqual(expectedStringWithoutAttrib.Type, actualStringWithoutAttrib.Type);

            Assert.AreEqual(expectedNumericWithoutAttrib.ColumnName, actualNumericWithoutAttrib.ColumnName);
            Assert.AreEqual(expectedNumericWithoutAttrib.Order, actualNumericWithoutAttrib.Order);
            Assert.AreEqual(expectedNumericWithoutAttrib.Type, actualNumericWithoutAttrib.Type);

            Assert.AreEqual(expectedBoolWithoutAttrib.ColumnName, actualBoolWithoutAttrib.ColumnName);
            Assert.AreEqual(expectedBoolWithoutAttrib.Order, actualBoolWithoutAttrib.Order);
            Assert.AreEqual(expectedBoolWithoutAttrib.Type, actualBoolWithoutAttrib.Type);

            Assert.AreEqual(expectedDateTimeWithoutAttrib.ColumnName, actualDateTimeWithoutAttrib.ColumnName);
            Assert.AreEqual(expectedDateTimeWithoutAttrib.Order, actualDateTimeWithoutAttrib.Order);
            Assert.AreEqual(expectedDateTimeWithoutAttrib.Type, actualDateTimeWithoutAttrib.Type);

            Assert.AreEqual(expectedObjectWithoutAttrib.ColumnName, actualObjectWithoutAttrib.ColumnName);
            Assert.AreEqual(expectedObjectWithoutAttrib.Order, actualObjectWithoutAttrib.Order);
            Assert.AreEqual(expectedObjectWithoutAttrib.Type, actualObjectWithoutAttrib.Type);

            Assert.IsNull(actualNoneWithoutAttrib);
        }

        [TestMethod]
        public void TestGetXlsxBindableInfo()
        {
            var bindable = new Bindable();

            var expectedString = new XlsxBindableInfo
                {
                ColumnName = "StringColumn",
                Order = 0,
                Type = XlsxDataType.String
            };

            var expectedNumeric = new XlsxBindableInfo
                {
                ColumnName = "NumericColumn",
                Order = 1,
                Type = XlsxDataType.Numeric
            };

            var expectedBool = new XlsxBindableInfo
                {
                ColumnName = "BoolColumn",
                Order = 2,
                Type = XlsxDataType.Boolean
            };

            var expectedDateTime = new XlsxBindableInfo
                {
                ColumnName = "DateColumn",
                Order = 3,
                Type = XlsxDataType.DateTime
            };

            var expectedObject = new XlsxBindableInfo
                {
                ColumnName = "ObjectColumn",
                Order = 4,
                Type = XlsxDataType.Object
            };

            var stringProperty = bindable.GetType().GetProperties().Single(x => x.Name == "StringBindableProperty");
            var numericProperty = bindable.GetType().GetProperties().Single(x => x.Name == "NumericBindableProperty");
            var boolProperty = bindable.GetType().GetProperties().Single(x => x.Name == "BoolBindableProperty");
            var dateTimeProperty = bindable.GetType().GetProperties().Single(x => x.Name == "DateTimeBindableProperty");
            var objectProperty = bindable.GetType().GetProperties().Single(x => x.Name == "ObjectBindableProperty");
            var noneProperty = bindable.GetType().GetProperties().Single(x => x.Name == "NoneBindableProperty");

            var actualString = stringProperty.GetXlsxBindableInfo();
            var actualNumeric = numericProperty.GetXlsxBindableInfo();
            var actualBool = boolProperty.GetXlsxBindableInfo();
            var actualDateTime = dateTimeProperty.GetXlsxBindableInfo();
            var actualObject = objectProperty.GetXlsxBindableInfo();
            var actualNone = noneProperty.GetXlsxBindableInfo();

            Assert.AreEqual(expectedString.ColumnName, actualString.ColumnName);
            Assert.AreEqual(expectedString.Order, actualString.Order);
            Assert.AreEqual(expectedString.Type, actualString.Type);

            Assert.AreEqual(expectedNumeric.ColumnName, actualNumeric.ColumnName);
            Assert.AreEqual(expectedNumeric.Order, actualNumeric.Order);
            Assert.AreEqual(expectedNumeric.Type, actualNumeric.Type);

            Assert.AreEqual(expectedBool.ColumnName, actualBool.ColumnName);
            Assert.AreEqual(expectedBool.Order, actualBool.Order);
            Assert.AreEqual(expectedBool.Type, actualBool.Type);

            Assert.AreEqual(expectedDateTime.ColumnName, actualDateTime.ColumnName);
            Assert.AreEqual(expectedDateTime.Order, actualDateTime.Order);
            Assert.AreEqual(expectedDateTime.Type, actualDateTime.Type);

            Assert.AreEqual(expectedObject.ColumnName, actualObject.ColumnName);
            Assert.AreEqual(expectedObject.Order, actualObject.Order);
            Assert.AreEqual(expectedObject.Type, actualObject.Type);

            Assert.IsNull(actualNone);

        }

        [TestMethod]
        public void TestGetXlsxDataType()
        {
            var bindable = new Bindable();

            var stringProperty = bindable.GetType().GetProperties().Single(x => x.Name == "StringBindablePropertyWithoutAttrib");
            var numericProperty = bindable.GetType().GetProperties().Single(x => x.Name == "NumericBindablePropertyWithoutAttrib");
            var boolProperty = bindable.GetType().GetProperties().Single(x => x.Name == "BoolBindablePropertyWithoutAttrib");
            var dateTimeProperty = bindable.GetType().GetProperties().Single(x => x.Name == "DateTimeBindablePropertyWithoutAttrib");
            var objectProperty = bindable.GetType().GetProperties().Single(x => x.Name == "ObjectBindablePropertyWithoutAttrib");

            const XlsxDataType expectedString = XlsxDataType.String;
            const XlsxDataType expectedNumeric = XlsxDataType.Numeric;
            const XlsxDataType expectedBool = XlsxDataType.Boolean;
            const XlsxDataType expectedDate = XlsxDataType.DateTime;
            const XlsxDataType expectedObject = XlsxDataType.Object;

            var actualString = stringProperty.GetXlsxDataType();
            var actualNumeric = numericProperty.GetXlsxDataType();
            var actualBool = boolProperty.GetXlsxDataType();
            var actualDate = dateTimeProperty.GetXlsxDataType();
            var actualObject = objectProperty.GetXlsxDataType();

            Assert.AreEqual(expectedString, actualString);
            Assert.AreEqual(expectedNumeric, actualNumeric);
            Assert.AreEqual(expectedBool, actualBool);
            Assert.AreEqual(expectedDate, actualDate);
            Assert.AreEqual(expectedObject, actualObject);
        }
    }
}
